package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackIndication;
import com.meshnetics.gb.stack.core.layer.StackLayer;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.stack.mac.type.GTSCharacteristics;
import com.meshnetics.gb.stack.mac.type.TypeGTSCharacteristics;
import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.Bitmap;
import com.meshnetics.gb.type.impl.zcl.TypeBitmap;
import com.meshnetics.gb.type.impl.zcl.TypeUInt;
import com.meshnetics.gb.type.impl.zcl.UInt;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACGtsIndication extends StackIndication {
    public static final byte CODE = 0x51;

    private final UInt deviceAddress;
    private final GTSCharacteristics gtsCharacs;
    private final Bitmap secAndAcl;


    public MACGtsIndication(short deviceAddress, GTSCharacteristics gtsCharacs, boolean securityUse, int aclEntry) {
        this(deviceAddress, gtsCharacs, securityUse, (byte) (aclEntry & 0xff));
    }

    public MACGtsIndication(short deviceAddress, GTSCharacteristics gtsCharacs, boolean securityUse, byte aclEntry) {
        this(new Short(deviceAddress), gtsCharacs, Boolean.valueOf(securityUse), new Byte(aclEntry));
    }

    public MACGtsIndication(Short deviceAddress, GTSCharacteristics gtsCharacs, Boolean securityUse, Byte aclEntry) {
        this((UInt) TypeUInt.UINT_16.fromObject(deviceAddress), gtsCharacs, securityUse, aclEntry);
    }

    public MACGtsIndication(UInt deviceAddress, GTSCharacteristics gtsCharacs, Boolean securityUse, Byte aclEntry) {
        this(deviceAddress, gtsCharacs, Utils.createBitmapSecAndAcl(securityUse.booleanValue(), aclEntry.intValue()));
    }

    public MACGtsIndication(ByteBuffer bb, RadioMACStackLayer layer) {
        super("macGtsIndication", StackEventType.LME_TYPE, null, layer);
        ByteUtils.ensureNotNull(bb);
        ByteUtils.ensureCapacity(bb, 4);
        this.deviceAddress = (UInt) TypeUInt.UINT_16.deserialize(bb);
        this.gtsCharacs = (GTSCharacteristics) TypeGTSCharacteristics.TYPE.deserialize(bb);
        this.secAndAcl = (Bitmap) TypeBitmap.BITMAP_8.deserialize(bb);
        if (bb.remaining() > 0) {
            throw new IllegalArgumentException("unexpected content of ByteBuffer, " + bb.remaining() + " bytes left");
        }
    }

    public MACGtsIndication(UInt deviceAddress, GTSCharacteristics gtsCharacs, Bitmap secAndAcl) {
        this(deviceAddress, gtsCharacs, secAndAcl, null);
    }

    public MACGtsIndication(UInt deviceAddress, GTSCharacteristics gtsCharacs, Bitmap secAndAcl, StackLayer source) {
        super("macGtsIndication", StackEventType.LME_TYPE, null, source);
        if (deviceAddress == null) {
            throw new NullPointerException("deviceAddress is null");
        }
        if (gtsCharacs == null) {
            throw new NullPointerException("gtsCharacs is null");
        }
        if (secAndAcl == null) {
            throw new NullPointerException("secAndAcl is null");
        }
        this.deviceAddress = deviceAddress.convert(TypeUInt.UINT_16);
        this.gtsCharacs = gtsCharacs;
        if (secAndAcl.getBits(5, 8) != 0) {
            throw new IllegalArgumentException("bits 5-7 of secAndAcl are reserved and should be all zeroes");
        }
        this.secAndAcl = secAndAcl;
    }

    public UInt getDeviceAddressType() {
        return deviceAddress;
    }

    public Short getDeviceAddress() {
        return (Short) deviceAddress.toObject();
    }

    public GTSCharacteristics getGtsCharacs() {
        return gtsCharacs;
    }

    public Bitmap getSecAndAclType() {
        return secAndAcl;
    }

    public boolean isSecurityUse() {
        return secAndAcl.getBit(0);
    }

    public int getAclEntry() {
        return secAndAcl.getBits(1, 5);
    }

    public String toString() {
        return getName() + '(' + deviceAddress + ',' + gtsCharacs + ',' + secAndAcl + ')';
    }
}
